﻿using Sirius.SystemDll;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using static Sirius.Log.Log;
using System.Text.Json;
using Sirius.Entity;
using Newtonsoft.Json.Linq;
using Sirius.Util;

namespace Sirius.Application
{
    //应用管理器
    public  class ApplicationManager
    {
        public static readonly Mutex eventMutex = new Mutex(false);
        public static Mutex EventMutex { get => eventMutex; }

        //定义应用集合
        public static List<Application> apps = new List<Application>();

        //加载应用
        public static void LoadApplication()
        {
            apps.Clear();
            string PluginPath = $"{AppDomain.CurrentDomain.SetupInformation.ApplicationBase}" + "Plugin";//应用目录
            try
            {
                //判断路径是否存在
                if (!Directory.Exists(PluginPath))
                    Directory.CreateDirectory(PluginPath);
                //获取当前目录下所有文件
                DirectoryInfo directory = new DirectoryInfo(PluginPath);
                FileInfo[] files = directory.GetFiles();

                List<FileInfo> fileList = new List<FileInfo>();
                foreach (FileInfo file in files)
                {
                    if (!PluginCompare(file.FullName, fileList) )
                    {
                        fileList.Add(file);
                    }
                    else
                    {
                        LogWar("CheckAppLication", "应用目录下存在重复应用，已跳过...");
                    }
                }


                foreach (FileInfo file in fileList)
                {
                    if (Path.GetExtension(file.FullName).ToLower() == ".dll")
                    {
                        Application app = new Application(file);
                        if (app.appInfo != null && app.appInfo.App_Name != null)
                        {
                            apps.Add(app);
                            LogSuc("LoadApplication", "[" + app.appInfo.App_Name + "]" + "加载成功！");

                        }
                        else
                        {
                            kernel32.FreeLibrary(app.instance);
                            LogErr("LoadApplication", "[" + file.Name + "]" + "AppInfo函数未公开，或不是Sirius应用！");
                        }
                    }
                }
            }
            catch (Exception ex)
            {

            }
        }


        /// <summary>
        /// 机器人被@事件
        /// </summary>
        /// <param name="data">原始数据</param>
        [System.Runtime.ExceptionServices.HandleProcessCorruptedStateExceptionsAttribute]
        public async static void PublicAtMessagePushForApplication(string data)
        {

            Message message;

            

            try
            {
                message = JsonSerializer.Deserialize<Message>(JsonDocument.Parse(data).RootElement.GetProperty("d").ToString());

                var authorID = message.Author.Id;
                var authorName = message.Author.Username;
                var channel_id = message.channel_Id;
                var content = message.Content;

                LogEvent("Bot被@事件", "成员:" + authorID + "[" + authorName + "]在频道" + channel_id + "发送了:" + content);
                foreach (var app in apps)
                {
                    int resultCode = app.Method.GuildAtMessage(data);

                    switch (resultCode)
                    {
                        case -1:
                            LogWar("消息事件", "应用消息解析失败！");
                            return;
                        case 0:
                            LogOut("消息事件", "忽略");
                            continue;
                        case 1:
                            LogOut("消息事件", "拦截");
                            return;
                    }

                }


            }
            catch (Exception ex)
            {
                LogWar("公域消息事件推送", "应用消息推送失败，请检查后再试..."+ex.ToString());
            }

        }
        

        /// <summary>
        /// 频道事件推送
        /// </summary>
        /// <param name="instance">事件类型</param>
        /// <param name="data">原始数据</param>
        public async static void Guild_eventPushForApplication(string instance,string data)
        {

            try
            {

                foreach (var app in apps)
                {
                    int resultCode = app.Method.eventGuild(instance,data);

                    switch (resultCode)
                    {
                        case -1:
                            LogWar("频道事件", "应用消息解析失败！");
                            return;
                        case 0:
                            LogOut("频道事件", "忽略");
                            continue;
                        case 1:
                            LogOut("频道事件", "拦截");
                            return;
                    }
                }
            }
            catch (Exception ex)
            {
                LogWar("频道事件", "应用消息推送失败，请检查后再试..." + ex.ToString());
            }
        }


        /// <summary>
        /// 子频道事件推送
        /// </summary>
        /// <param name="instance">事件类型</param>
        /// <param name="data">原始数据</param>
        public async static void Channel_eventPushForApplication(string instance ,string data)
        {
            try
            {
                foreach (var socket in WebSocket.WebSocketAPI.WebSocketServerAPI.clientList)
                {
                    socket.Send(data);
                }
                foreach (var app in apps)
                {
                    int resultCode = app.Method.eventChannel(instance, data);

                    switch (resultCode)
                    {
                        case -1:
                            LogWar("子频道事件", "应用消息解析失败！");
                            return;
                        case 0:
                            LogOut("子频道事件", "忽略");
                            continue;
                        case 1:
                            LogOut("子频道事件h", "拦截");
                            return;
                    }
                }
            }
            catch (Exception ex)
            {
                LogWar("子频道事件", "应用消息推送失败，请检查后再试..." + ex.ToString());
            }
        }
        
        /// <summary>
        /// 机器人信息初始化
        /// </summary>
        /// <param name="data">原始数据</param>
        public async static void BotInfoPushForApplication(string data)
        {
            try
            {
                foreach (var socket in WebSocket.WebSocketAPI.WebSocketServerAPI.clientList)
                {
                    socket.Send(data);
                }
                foreach (var app in apps)
                {

                    app.Method.botInit(data);

                }

            }
            catch(Exception e)
            {
                LogWar("BotInfo", "InitBot函数不存在，或未公开！");
            }
        }

        /// <summary>
        /// 私域消息事件推送
        /// </summary>
        /// <param name="instance">事件类型</param>
        /// <param name="data">原始数据</param>
        public async static void PrivateMessagePushForApplication(string instance,string data)
        {
            try
            {
                Message message;
                if (!instance.Contains("DELETE"))
                {
                    message = JsonSerializer.Deserialize<Message>(JsonDocument.Parse(data).RootElement.GetProperty("d").ToString());
                    string authorID = message.Author.Id;
                    string authorName = message.Author.Username;
                    string channel_id = message.channel_Id;
                    string content = message.Content;
                    string imgData = null;
                    if (message.Attachments != null)
                    {
                        for(int i = 0; i < message.Attachments.Length; i++)
                        {
                            imgData += "图片[" + (i + 1) + "]:链接->" + message.Attachments[i].url + "\n";
                        }
                    }
                    if (EmojiFormat.containsEmoji(content))
                    {
                        LogWar("私域频道消息事件[Emoji编码版]", "成员:" + authorID + "[" + authorName + "]在子频道" + channel_id + "发送了:" + EmojiFormat.EmojiToString(content) + "\n" + imgData);
                    }
                    else
                    {
                        
                        LogEvent("私域频道消息事件", "成员:" + authorID + "[" + authorName + "]在子频道" + channel_id + "发送了:" + content + "\n" + imgData);
                    }
                }
                else
                {
                    var json = JsonDocument.Parse(  data);
                    var authorID = json.RootElement.GetProperty("d").GetProperty("message").GetProperty("author").GetProperty("id").GetString();
                    var authorName = json.RootElement.GetProperty("d").GetProperty("message").GetProperty("author").GetProperty("username").GetString();
                    var channel_id = json.RootElement.GetProperty("d").GetProperty("message").GetProperty("channel_id").GetString();
                    var msg = json.RootElement.GetProperty("d").GetProperty("message").GetProperty("id").GetString();
                    LogEvent("私域频道消息事件", "成员:" + authorID + "[" + authorName + "]在子频道" + channel_id + "撤回了消息:" + msg);
                }
                foreach (var app in apps)
                {
                    int resultCode = app.Method.eventGuildMessage(instance,data);

                    switch (resultCode)
                    {
                        case -1:
                            LogWar("消息事件", "应用消息解析失败！");
                            return;
                        case 0:
                            LogOut("消息事件", "忽略");
                            continue;
                        case 1:
                            LogOut("消息事件", "拦截");
                            return;
                    }
                }
            }
            catch (Exception ex)
            {
                LogWar("私域消息事件推送", "应用消息推送失败，请检查后再试..." + ex.ToString());
            }
        }

        /// <summary>
        /// 私信事件推送
        /// </summary>
        /// <param name="data">原始数据</param>
        public async static void DirectMessagePushForApplication(string data)
        {
            try
            {
                //创建消息对象
                Message message;
                //进行反序列化，解析d字段
                message = JsonSerializer.Deserialize<Message>(JsonDocument.Parse(data).RootElement.GetProperty("d").ToString());
                //获取私信人员名称
                string authorName = message.Author.Username;
                //获取私信人员ID
                string authorID = message.Author.Id;
                //获取私信会话关联的子频道 id   
                string channel_id = message.channel_Id;
                //获取内容
                string content = message.Content;
                //获取私信会话关联的频道ID
                string guild_id = message.guild_Id;
                //图片数据
                string imgData = null;
                
                if (message.Attachments != null)
                {
                    for (int i = 0; i < message.Attachments.Length; i++)
                    {
                        imgData += "图片[" + (i + 1) + "]:链接->" + message.Attachments[i].url + "\n";
                    }
                }
                if (EmojiFormat.containsEmoji(content))
                {
                    LogWar("私信会话事件推送->Emoji编码版", "成员:" + authorID + "[" + authorName + "]在子频道" + channel_id + "发送了:" + EmojiFormat.EmojiToString(content) + "\n" + imgData);
                }
                else
                {
                    LogEvent("私信会话事件推送", "成员:" + authorID + "[" + authorName + "]在子频道" + channel_id + "发送了:" + content + "\n" + imgData);
                }
                foreach (var app in apps)
                {
                    int resultCode = app.Method.eventPrivateMessage(data);

                    switch (resultCode)
                    {
                        case -1:
                            LogWar("消息事件", "应用消息解析失败！");
                            return;
                        case 0:
                            LogOut("消息事件", "忽略");
                            continue;
                        case 1:
                            LogOut("消息事件", "拦截");
                            return;
                    }
                }
            }
            catch (Exception ex)
            {
                LogWar("私信会话事件推送", "应用消息推送失败，请检查后再试..." + ex.ToString());
            }
        }

        /// <summary>
        /// 频道成员事件推送
        /// </summary>
        /// <param name="instance">事件类型</param>
        /// <param name="data">原始数据</param>
        public async static void GuildMemberPushForApplication(string instance,string data)
        {
            try
            {
                var json = JObject.Parse(data);
                var eventType = json["t"].ToString();
                var username = json["d"]["user"]["username"].ToString();
                var guild_id = json["d"]["guild_id"].ToString();
                switch (eventType)
                {
                    case "GUILD_MEMBER_ADD":
                        LogEvent("频道成员加入", username + "加入了频道:" + "频道ID->" + guild_id);
                        foreach (var app in apps)
                        {
                            int resultCode = app.Method.eventGuildMember(instance,data);

                            switch (resultCode)
                            {
                                case -1:
                                    LogWar("消息事件", "应用消息解析失败！");
                                    return;
                                case 0:
                                    LogOut("消息事件", "忽略");
                                    continue;
                                case 1:
                                    LogOut("消息事件", "拦截");
                                    return;
                            }

                        }
                        break;
                    case "GUILD_MEMBER_UPDATE":
                        var update_Name = json["d"]["nick"].ToString();
                        LogEvent("频道成员信息更新", username + "在频道->"+guild_id+"更新了昵称" + update_Name);
                        foreach (var app in apps)
                        {
                            int resultCode = app.Method.eventGuildMember(instance, data);

                            switch (resultCode)
                            {
                                case -1:
                                    LogWar("消息事件", "应用消息解析失败！");
                                    return;
                                case 0:
                                    LogOut("消息事件", "忽略");
                                    continue;
                                case 1:
                                    LogOut("消息事件", "拦截");
                                    return;
                            }

                        }
                        break;
                    case "GUILD_MEMBER_REMOVE":
                        LogEvent("频道成员退出或被移除", username + "退出或被移除频道->" + guild_id);
                        foreach (var app in apps)
                        {
                            int resultCode = app.Method.eventGuildMember(instance, data);

                            switch (resultCode)
                            {
                                case -1:
                                    LogWar("消息事件", "应用消息解析失败！");
                                    return;
                                case 0:
                                    LogOut("消息事件", "忽略");
                                    continue;
                                case 1:
                                    LogOut("消息事件", "拦截");
                                    return;
                            }

                        }
                        break;
                }
            }catch (Exception ex)
            {
                LogWar("频道成员事件推送", "频道成员事件推送失败" + ex.Message);
            }
        }

        /// <summary>
        /// 表情表态事件推送
        /// </summary>
        /// <param name="instance">事件类型</param>
        /// <param name="data">原始数据</param>
        public async static void MessageReactionPushForApplication(string instance,string data)
        {
            try
            {
                var json = JObject.Parse(data);
                var eventType = json["t"].ToString();
                var channel_id = json["d"]["channel_id"].ToString();
                var emoji_id = json["d"]["emoji"]["id"].ToString();
                var emoji_Type = json["d"]["emoji"]["type"].ToString();
                var msg_id = json["d"]["target"]["id"].ToString();
                var user_id = json["d"]["user_id"].ToString();
                switch (eventType)
                {
                    case "MESSAGE_REACTION_ADD":
                        LogEvent("表情表态事件", "用户:" + user_id + "在子频道:" + channel_id + "对消息:" + msg_id + "进行了表情表态:类型->" + emoji_Type + "<emoji:" + emoji_id + ">");
                        foreach (var app in apps)
                        {
                            int resultCode = app.Method.eventMessageReaction(instance, data);
                            switch (resultCode)
                            {
                                case -1:
                                    LogWar("表情表态事件", "应用消息解析失败！");
                                    return;
                                case 0:
                                    LogOut("表情表态事件", "忽略");
                                    continue;
                                case 1:
                                    LogOut("表情表态事件", "拦截");
                                    return;
                            }
                        }
                        break;
                    case "MESSAGE_REACTION_REMOVE":
                        LogEvent("表情表态事件", "用户:" + user_id + "在子频道:" + channel_id + "对消息:" + msg_id + "取消了表情表态:类型->" + emoji_Type + "<emoji:" + emoji_id + ">");
                        foreach (var app in apps)
                        {
                            int resultCode = app.Method.eventMessageReaction(instance, data);
                            switch (resultCode)
                            {
                                case -1:
                                    LogWar("表情表态事件", "应用消息解析失败！");
                                    return;
                                case 0:
                                    LogOut("表情表态事件", "忽略");
                                    continue;
                                case 1:
                                    LogOut("表情表态事件", "拦截");
                                    return;
                            }
                        }
                        break;
                }
            }
            catch (Exception ex)
            {
                LogWar("表情表态推送", "表情表态事件推送失败" + ex.Message);
            }
        }

        /// <summary>
        /// 互动消息推送
        /// </summary>
        /// <param name="data">原始数据</param>
        public async static void InteractionPushForApplication(string data)
        {
            try
            {
                var json = JObject.Parse(data);
                var event_id = json["id"].ToString();
                var application_id = json["d"]["application_id"].ToString();
                var channel_id = json["d"]["channel_id"].ToString();
                var button_data = json["d"]["data"]["resolved"]["button_data"].ToString();
                var button_id = json["d"]["data"]["resolved"]["button_id"].ToString();
                var message_id = json["d"]["data"]["resolved"]["message_id"].ToString();
                var user_id = json["d"]["data"]["resolved"]["user_id"].ToString();
                var guild_id = json["d"]["guild_id"].ToString();
                foreach (var app in apps)
                {
                    int resultCode = app.Method.eventInteractionMessage(data, event_id, message_id, button_id, button_data, user_id, channel_id, guild_id);
                    switch (resultCode)
                    {
                        case -1:
                            LogWar("互动消息事件", "应用消息解析失败！");
                            return;
                        case 0:
                            LogOut("互动消息事件", "忽略");
                            continue;
                        case 1:
                            LogOut("互动消息事件", "拦截");
                            return;
                    }
                }
            }
            catch(Exception e)
            {
                LogWar("互动消息事件推送失败", e.Message);
            }
        }
        public static bool CompareFile(string firstFile, string secondFile)
        {
            if (!File.Exists(firstFile) || !File.Exists(secondFile))
            {
                return false;
            }
            if (firstFile == secondFile)
            {
                return true;
            }
            int firstFileByte = 0;
            int secondFileByte = 0;
            FileStream secondFileStream = new FileStream(secondFile, FileMode.Open);
            FileStream firstFileStream = new FileStream(firstFile, FileMode.Open);
            if (firstFileStream.Length != secondFileStream.Length)
            {
                firstFileStream.Close();
                secondFileStream.Close();
                return false;
            }
            do
            {
                firstFileByte = firstFileStream.ReadByte();
                secondFileByte = secondFileStream.ReadByte();
            } while ((firstFileByte == secondFileByte) && (firstFileByte != -1));
            firstFileStream.Close();
            secondFileStream.Close();
            return (firstFileByte == secondFileByte);
        }

        public static bool PluginCompare(string FileName,List<FileInfo>fileList)
        {
            foreach(FileInfo file in fileList)
            {
                if(CompareFile(FileName,file.FullName))
                {
                    return true;
                }
            }
            return false;
        }

        public static void loadOneApplication(FileInfo appFile)
        {
            if (Path.GetExtension(appFile.FullName).ToLower() == ".dll")
            {
                Application app = new Application(appFile);
                if (app.appInfo != null && app.appInfo.App_Name != null)
                {
                    apps.Add(app);
                    LogSuc("LoadApplication", "[" + app.appInfo.App_Name + "]" + "加载成功！");
                }
                else
                {
                    kernel32.FreeLibrary(app.instance);
                    appFile.Delete();
                    LogErr("LoadApplication", "[" + appFile.Name + "]" + "AppInfo函数未公开，或不是Sirius应用！");
                }
            }
        }

    }

}
